package cn.tedu.charging.device.dao.repository.impl;

import cn.tedu.charging.device.dao.repository.ChargingStationCacheRepository;
import cn.tedu.charging.device.pojo.po.ChargingStationPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.BoundGeoOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Repository("GEOANDNoShareHash")
public class ChargingStationCacheGEOANDNoShareHashRepositoryImpl implements ChargingStationCacheRepository {
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public void saveStations2Redis(List<ChargingStationPO> stationPOS) {
        Map<Integer, Point> map = new HashMap<>();
        Map<String,Map<String,Object>> stationPOMap = new HashMap<>();
        HashOperations hashOperations = redisTemplate.opsForHash();
        for (ChargingStationPO stationPO : stationPOS){
            BigDecimal stationLng = stationPO.getStationLng();
            BigDecimal stationLat = stationPO.getStationLat();

            String lngEngineeringString = stationLng.toEngineeringString();
            Double lng = Double.parseDouble(lngEngineeringString);

            String latEngineeringString = stationLat.toEngineeringString();
            Double lat = Double.valueOf(latEngineeringString);

            Point point = new Point(lng,lat);
            Integer stationId = stationPO.getId();
            map.put(stationId,point);

            String bigKey = "station_info_hash_no_share_" + stationId;
            Map<String,Object> smallMap = getSmallMap(stationPO);
            hashOperations.putAll(bigKey,smallMap);
        }
        BoundGeoOperations stations = redisTemplate.boundGeoOps("stations-geo");
        stations.add(map);
    }

    private Map<String, Object> getSmallMap(ChargingStationPO stationPO) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", stationPO.getId());
        map.put("stationCode", stationPO.getStationCode());
        map.put("stationName", stationPO.getStationName());
        map.put("deviceNumber", stationPO.getDeviceNumber());
        map.put("acGunNumber", stationPO.getAcGunNumber());
        map.put("dcGunNumber", stationPO.getDcGunNumber());
        map.put("acRatePower", stationPO.getAcRatePower());
        map.put("dcRatePower", stationPO.getDcRatePower());
        map.put("province", stationPO.getProvince());
        map.put("city", stationPO.getCity());
        map.put("address", stationPO.getAddress());
        map.put("stationLng", stationPO.getStationLng());
        map.put("stationLat", stationPO.getStationLat());
        map.put("devicePower", stationPO.getDevicePower());
        map.put("stationModel", stationPO.getStationModel());
        map.put("stationStatus", stationPO.getStationStatus());
        map.put("stationType", stationPO.getStationType());
        map.put("createTime", stationPO.getCreateTime());
        map.put("updateTime", stationPO.getUpdateTime());
        map.put("operatorId", stationPO.getOperatorId());
        map.put("parkFee", stationPO.getParkFee());
        map.put("deleted", stationPO.getDeleted());
        return map;
    }

    @Override
    public List<ChargingStationPO> getStationsFromRedis(Double longitude, Double latitude, Double distance) {
        BoundGeoOperations stations = redisTemplate.boundGeoOps("stations-geo");

        HashOperations hashOperations = redisTemplate.opsForHash();

        Circle circle = getCircle(longitude,latitude,distance);
        log.debug("查询半径为{}的圆",circle);
        GeoResults<RedisGeoCommands.GeoLocation<Integer>> radius = stations.radius(circle);
        log.debug("查询到的结果为:{}",radius);

        List<ChargingStationPO> stationPOS = new ArrayList<>();
        for (GeoResult<RedisGeoCommands.GeoLocation<Integer>> geoLocationGeoResult : radius) {
            RedisGeoCommands.GeoLocation<Integer> content = geoLocationGeoResult.getContent();
            Integer stationId = content.getName();

            String bigKey = "station_info_hash_no_share_" + stationId;
            Map<String,Object> entries = hashOperations.entries(bigKey);
            ChargingStationPO stationPO = getStationPO(entries);
            stationPOS.add(stationPO);
        }
        log.debug("查询到的结果为:{}",stationPOS);
        return stationPOS;
    }

    private ChargingStationPO getStationPO(Map<String, Object> entries) {
        ChargingStationPO stationPO = new ChargingStationPO();
        stationPO.setId((Integer) entries.get("id"));
        stationPO.setStationCode((String) entries.get("stationCode"));
        stationPO.setStationName((String) entries.get("stationName"));
        stationPO.setDeviceNumber((Integer) entries.get("deviceNumber"));
        stationPO.setAcGunNumber((Integer) entries.get("acGunNumber"));
        stationPO.setDcGunNumber((Integer) entries.get("dcGunNumber"));
        stationPO.setAcRatePower((Integer) entries.get("acRatePower"));
        stationPO.setDcRatePower((Integer) entries.get("dcRatePower"));
        stationPO.setProvince((String) entries.get("province"));
        stationPO.setCity((String) entries.get("city"));
        stationPO.setAddress((String) entries.get("address"));
        stationPO.setStationLng((BigDecimal) entries.get("stationLng"));
        stationPO.setStationLat((BigDecimal) entries.get("stationLat"));
        stationPO.setDevicePower((Integer) entries.get("devicePower"));
        stationPO.setStationModel((Integer) entries.get("stationModel"));
        stationPO.setStationStatus((Integer) entries.get("stationStatus"));
        stationPO.setStationType((Integer) entries.get("stationType"));
        stationPO.setCreateTime((Date) entries.get("createTime"));
        stationPO.setUpdateTime((Date) entries.get("updateTime"));
        stationPO.setOperatorId((Integer) entries.get("operatorId"));
        stationPO.setParkFee((BigDecimal) entries.get("parkFee"));
        stationPO.setDeleted((Integer) entries.get("deleted"));
        return stationPO;
    }

    private Circle getCircle(Double longitude,Double latitude,Double distance){
        Point point = new Point(longitude,latitude);
        Distance geoDistance = new Distance(distance, Metrics.KILOMETERS);
        Circle circle = new Circle(point, geoDistance);
        return circle;
    }
}
